package com.uxbee.service;

import java.util.ArrayList;
import java.util.List;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import com.uxbee.pojo.HtmlData;

// 获取页面中的链接
public class LinkParser {
	
	public static int width = 5;
	
	public static int height = 5;

	// 获取页面中的链接
	public static List<HtmlData> extracLinks(HtmlData htmlData,
			LinkFilter filter) {
		// 验证深度默认深度5
		if (htmlData.getLevel() > height) {
			return null;
		}

		List<HtmlData> htmlDataList = null;
		try {
			Parser parser = new Parser(htmlData.getUrl());
			
			String encoding = getCode(parser);
			parser.reset();
			if (encoding != null && encoding.length() > 0){
				parser.setEncoding(encoding);
			}
			// parser.setEncoding("UTF-8");
			// OrFilter 来设置过滤 <a> 标签，和 <frame> 标签
			OrFilter linkFilter = getOrFilter();
			// 得到所有经过过滤的标签
			NodeList list = parser.extractAllNodesThatMatch(linkFilter);
			if (list == null || list.size() == 0){
				Parser rep = new Parser(htmlData.getUrl());
				if (encoding != null && encoding.length() > 0) {
					rep.setEncoding(encoding);
				}
				NodeFilter ret = new TagNameFilter("body");
				list = rep.extractAllNodesThatMatch(ret);
			}
			// 获取链接列表并且验证广度默认广度5
			htmlDataList = getUrl(htmlData, filter, list, width);

		}
		catch (ParserException e) {
			e.printStackTrace();
		}

		return htmlDataList;
	}

	// 获取页面编码兼容HTML5
	public static String getCode(Parser parser) throws ParserException {

		Parser p = new Parser(parser.getURL());
		
		NodeFilter tagFilter = new TagNameFilter("meta");
		HasAttributeFilter haf1 = new HasAttributeFilter("charset");
		HasAttributeFilter haf2 = new HasAttributeFilter("http-equiv", "Content-Type");
		OrFilter orf = new OrFilter(haf1, haf2);
		AndFilter af = new AndFilter(tagFilter, orf);
		NodeList nodes = null;
		boolean isException = false;
		try {
			p.setEncoding("gbk");
			nodes = p.extractAllNodesThatMatch(af);
			isException = false;
		}
		catch (Exception e) {
			isException = true;
			System.out.println(e);
		}
		if (isException){
			try {
				p.reset();
				p.setEncoding("utf-8");
				nodes = p.extractAllNodesThatMatch(af);
				isException = false;
			}
			catch (Exception e) {
				isException = true;
				System.out.println(e);
			}
		}
		String encoding = null;
		if (nodes != null) {
			TagNode liTag = (TagNode) nodes.elementAt(0);
			if (liTag != null){
				String metaHtml = liTag.toHtml();
				encoding = metaHtml.replaceAll("^.*charset\\s{0,}=[\'\"]{0,}", "");
				encoding = encoding.replaceAll("[\"\'].*$", "");
				encoding = encoding.replaceAll("\\s{1,}", "");
			}
		}
		return encoding;
	}

	// 设置过滤标签
	private static OrFilter getOrFilter() {
		// 过滤 <frame >标签的 filter，用来提取 frame 标签里的 src 属性所表示的链接
		NodeFilter frameFilter = new NodeFilter() {

			private static final long serialVersionUID = -7074935221997870406L;

			public boolean accept(Node node) {
				if (node.getText().startsWith("frame src=")) {
					return true;
				}
				else {
					return false;
				}
			}
		};
		// OrFilter 来设置过滤 <a> 标签，和 <frame> 标签
		return new OrFilter(new NodeClassFilter(LinkTag.class), frameFilter);
	}

	// 获取链接
	private static List<HtmlData> getUrl(HtmlData htmlData, LinkFilter filter,
			NodeList list, int count) {
		List<HtmlData> htmlDataList = new ArrayList<HtmlData>();
		for (int i = 0; i < list.size(); i++) {
			if (htmlDataList.size() > count) {
				break;
			}
			Node tag = list.elementAt(i);
			if (tag instanceof LinkTag)// <a> 标签
			{
				LinkTag link = (LinkTag) tag;
				String linkUrl = link.getLink();// url
				if (linkUrl != null){
					linkUrl = linkUrl.replaceAll("[#].*$", "");
				}
				if (filter.accept(htmlData.getMainUrl(), linkUrl)) {
					HtmlData tempHtmlData = new HtmlData();
					tempHtmlData.setUrl(linkUrl);
					tempHtmlData.setLevel(htmlData.getLevel() + 1);
					tempHtmlData.setMainUrl(htmlData.getMainUrl());
					boolean repair = false;
					// 链接重复的场合不保存链接
					for (int j = 0; j < htmlDataList.size(); j++) {
						HtmlData hd = htmlDataList.get(j);
						if (linkUrl.equals(hd.getUrl())) {
							repair = true;
							break;
						}
					}
					for (int j = 0; j < LinkLoad.resHtmlDataList.size()
							&& !repair; j++) {
						HtmlData hd = LinkLoad.resHtmlDataList.get(j);
						if (linkUrl.equals(hd.getUrl())) {
							repair = true;
							break;
						}
					}

					if (!repair) {
						htmlDataList.add(tempHtmlData);
					}
				}
			}
			else// <frame> 标签
			{
				// 提取 frame 里 src 属性的链接如 <frame src="test.html"/>
				String frame = tag.getText();
				int start = frame.indexOf("src=");
				if (start == -1){
					continue;
				}
				frame = frame.substring(start);
				int end = frame.indexOf(" ");
				if (end == -1) {
					end = frame.indexOf(">");
				}
				String frameUrl = frame.substring(5, end - 1);
				if (frameUrl != null){
					frameUrl = frameUrl.replaceAll("[#].*$", "");
				}
				if (filter.accept(htmlData.getMainUrl(), frameUrl)) {
					HtmlData tempHtmlData = new HtmlData();
					tempHtmlData.setUrl(frameUrl);
					tempHtmlData.setLevel(htmlData.getLevel() + 1);
					tempHtmlData.setMainUrl(htmlData.getMainUrl());
					boolean repair = false;
					// 链接重复的场合不保存链接
					for (int j = 0; j < htmlDataList.size(); j++) {
						HtmlData hd = htmlDataList.get(j);
						if (frameUrl.equals(hd.getUrl())) {
							repair = true;
							break;
						}
					}
					for (int j = 0; j < LinkLoad.resHtmlDataList.size()
							&& !repair; j++) {
						HtmlData hd = LinkLoad.resHtmlDataList.get(j);
						if (frameUrl.equals(hd.getUrl())) {
							repair = true;
							break;
						}
					}

					if (!repair) {
						htmlDataList.add(tempHtmlData);
					}
				}
			}
		}
		return htmlDataList;
	}
}
